{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Paddlepaddle实现逻辑回归 - 识别猫\n",
    "\n",
    "欢迎大家来到这个有趣的实验！在这个实验中，大家将学使用PaddlePaddle实现Logistic回归模型来解决识别猫的问题，一步步跟随内容完成训练，加深对逻辑回归理论内容的理解并串联各个知识点，收获对神经网络和深度学习概念的整体把握。 \n",
    "\n",
    "** 你将学会 **\n",
    "\n",
    "- 预处理图片数据\n",
    "\n",
    "- 利用PaddlePaddle框架实现Logistic回归模型：\n",
    "\n",
    "在开始实验之前，让我们简单介绍一下图片处理的相关知识：\n",
    "\n",
    "** 图片处理 **\n",
    "\n",
    "由于识别猫问题涉及到图片处理指示，这里对计算机如何保存图片做一个简单的介绍。在计算机中，图片被存储为三个独立的矩阵，分别对应图3-6中的红、绿、蓝三个颜色通道，如果图片是64*64像素的，就会有三个64*64大小的矩阵，要把这些像素值放进一个特征向量中，需要定义一个特征向量X，将三个颜色通道中的所有像素值都列出来。如果图片是64*64大小的，那么特征向量X的总纬度就是64*64*3，也就是12288维。这样一个12288维矩阵就是Logistic回归模型的一个训练数据。\n",
    "\n",
    "<img src=\"images/image_to_vector.png\" style=\"width:550px;height:300px;\">\n",
    "\n",
    "现在，让我们正式进入实验吧！\n",
    "\n",
    "## 1 - 引用库\n",
    "\n",
    "首先，载入几个需要用到的库，它们分别是：\n",
    "\n",
    "- numpy：一个python的基本库，用于科学计算\n",
    "- matplotlib.pyplot：用于生成图，在验证模型准确率和展示成本变化趋势时会使用到\n",
    "- lr_utils：定义了load_dataset()方法用于载入数据\n",
    "- paddle.v2：PaddlePaddle深度学习框架"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "import numpy as np\n",
    "\n",
    "import lr_utils\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "import paddle.v2 as paddle\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2 - 数据预处理\n",
    "\n",
    "这里简单介绍数据集及其结构。数据集以hdf5文件的形式存储，包含了如下内容：\n",
    "\n",
    "- 训练数据集：包含了m_train个图片的数据集，数据的标签（Label）分为cat（y=1）和non-cat（y=0）两类。\n",
    "- 测试数据集：包含了m_test个图片的数据集，数据的标签（Label）同上。\n",
    "\n",
    "单个图片数据的存储形式为（num_x, num_x, 3），其中num_x表示图片的长或宽（数据集图片的长和宽相同），数字3表示图片的三通道（RGB）。\n",
    "在代码中使用一行代码来读取数据，读者暂不需要了解数据的读取过程，只需调用load_dataset()方法，并存储五个返回值，以便后续的使用。\n",
    "    \n",
    "需要注意的是，添加“_orig”后缀表示该数据为原始数据，因为之后还需要对数据进行进一步处理。未添加“_orig”的数据则表示之后不对该数据作进一步处理。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = lr_utils.load_dataset()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "y = [0], it's a 'non-cat' picture.\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f41385ca9d0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 图片示例\n",
    "index = 23\n",
    "plt.imshow(train_set_x_orig[index])\n",
    "print (\"y = \" + str(train_set_y[:, index]) + \", it's a '\" + classes[np.squeeze(train_set_y[:, index])].decode(\"utf-8\") +  \"' picture.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获取数据后的下一步工作是获得数据的相关信息，如训练样本个数m_train、测试样本个数m_test和图片的长度或宽度num_x，使用numpy.array.shape来获取数据的相关信息。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** 练习: ** 查看样本信息:\n",
    "    - m_train (训练样本数)\n",
    "    - m_test (测试样本数)\n",
    "    - num_px （图片长或宽）\n",
    "`train_set_x_orig` 是一个(m_train, num_px, num_px, 3)形状的numpy数组。举个例子，你可以使用`train_set_x_orig.shape[0]`来获得 `m_train`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练样本数: m_train = None\n",
      "测试样本数: m_test = None\n",
      "图片高度/宽度: num_px = None\n",
      "图片大小: (None, None, 3)\n",
      "train_set_x shape: (209, 64, 64, 3)\n",
      "train_set_y shape: (1, 209)\n",
      "test_set_x shape: (50, 64, 64, 3)\n",
      "test_set_y shape: (1, 50)\n"
     ]
    }
   ],
   "source": [
    "### START CODE HERE ### (≈ 3 lines of code)\n",
    "m_train = None\n",
    "m_test = None\n",
    "num_px = None\n",
    "### END CODE HERE ###\n",
    "\n",
    "print (\"训练样本数: m_train = \" + str(m_train))\n",
    "print (\"测试样本数: m_test = \" + str(m_test))\n",
    "print (\"图片高度/宽度: num_px = \" + str(num_px))\n",
    "print (\"图片大小: (\" + str(num_px) + \", \" + str(num_px) + \", 3)\")\n",
    "print (\"train_set_x shape: \" + str(train_set_x_orig.shape))\n",
    "print (\"train_set_y shape: \" + str(train_set_y.shape))\n",
    "print (\"test_set_x shape: \" + str(test_set_x_orig.shape))\n",
    "print (\"test_set_y shape: \" + str(test_set_y.shape))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**期望输出：**: \n",
    "<table style=\"width:15%\">\n",
    "  <tr>\n",
    "    <td>**m_train**</td>\n",
    "    <td> 209 </td> \n",
    "  </tr>\n",
    "  \n",
    "  <tr>\n",
    "    <td>**m_test**</td>\n",
    "    <td> 50 </td> \n",
    "  </tr>\n",
    "  \n",
    "  <tr>\n",
    "    <td>**num_px**</td>\n",
    "    <td> 64 </td> \n",
    "  </tr>\n",
    "  \n",
    "</table>\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接下来需要对数据作进一步处理，为了便于训练，你可以忽略图片的结构信息，将包含图像长、宽和通道数信息的三维数组压缩成一维数组，图片数据的形状将由(64, 64, 3)转化为(64 * 64 * 3, 1)。\n",
    "\n",
    "** 练习：** \n",
    "\n",
    "将数据形状由(64, 64, 3)转化为(64 * 64 * 3, 1)。\n",
    "\n",
    "** 技巧：**\n",
    "\n",
    "我们可以使用一个小技巧来将(a,b,c,d)形状的矩阵转化为(b$*$c$*$d, a)形状的矩阵: \n",
    "\n",
    "```python\n",
    "X_flatten = X.reshape(X.shape[0], -1)\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train_set_x_flatten shape: (209, 12288)\n",
      "train_set_y shape: (1, 209)\n",
      "test_set_x_flatten shape: (50, 12288)\n",
      "test_set_y shape: (1, 50)\n"
     ]
    }
   ],
   "source": [
    "# 转换数据形状\n",
    "\n",
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "train_set_x_flatten = None\n",
    "test_set_x_flatten = None\n",
    "### END CODE HERE ###\n",
    "\n",
    "print (\"train_set_x_flatten shape: \" + str(train_set_x_flatten.shape))\n",
    "print (\"train_set_y shape: \" + str(train_set_y.shape))\n",
    "print (\"test_set_x_flatten shape: \" + str(test_set_x_flatten.shape))\n",
    "print (\"test_set_y shape: \" + str(test_set_y.shape))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**期望输出**: \n",
    "\n",
    "<table style=\"width:35%\">\n",
    "  <tr>\n",
    "    <td>**train_set_x_flatten shape**</td>\n",
    "    <td> (209, 12288)</td> \n",
    "  </tr>\n",
    "  <tr>\n",
    "    <td>**train_set_y shape**</td>\n",
    "    <td>(1, 209)</td> \n",
    "  </tr>\n",
    "  <tr>\n",
    "    <td>**test_set_x_flatten shape**</td>\n",
    "    <td>(50, 12288)</td> \n",
    "  </tr>\n",
    "  <tr>\n",
    "    <td>**test_set_y shape**</td>\n",
    "    <td>(1, 50)</td> \n",
    "  </tr>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在开始训练之前，还需要对数据进行归一化处理。图片采用红、绿、蓝三通道的方式来表示颜色，每个通道的单个像素点都存储着一个0-255的像素值，所以图片的归一化处理十分简单，只需要将数据集中的每个值除以255即可，但需要注意的是结果值应为float类型，直接除以255会导致结果错误，在Python中除以255.即可将结果转化为float类型。\n",
    "现在让我们来归一化数据吧！\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "train_set_x = None\n",
    "test_set_x = None\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "为了方便后续的测试工作，添加了合并数据集和标签集的操作，使用numpy.hstack实现numpy数组的横向合并。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_set = np.hstack((train_set_x, train_set_y.T))\n",
    "test_set = np.hstack((test_set_x, test_set_y.T))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color='blue'>\n",
    "**经过上面的实验，大家应该记住:**\n",
    "\n",
    "对数据进行预处理的一般步骤是:\n",
    "    \n",
    "- 了解数据的维度和形状等信息，例如(m_train, m_test, num_px, ...)\n",
    "- 降低数据纬度，例如将数据维度(num_px, num_px, 3)转化为(num_px \\* num_px \\* 3, 1)\n",
    "- 数据归一化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "至此我们就完成了数据预处理工作！在接下来的练习中我们将构造reader，用于读取数据。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3 - 构造reader\n",
    "\n",
    "构造read_data()函数，来读取训练数据集train_set或者测试数据集test_set。它的具体实现是在read_data()函数内部构造一个reader()，使用yield关键字来让reader()成为一个Generator（生成器），注意，yield关键字的作用和使用方法类似return关键字，不同之处在于yield关键字可以构造生成器（Generator）。虽然我们可以直接创建一个包含所有数据的列表，但是由于内存限制，我们不可能创建一个无限大的或者巨大的列表，并且很多时候在创建了一个百万数量级别的列表之后，我们却只需要用到开头的几个或几十个数据，这样造成了极大的浪费，而生成器的工作方式是在每次循环时计算下一个值，不断推算出后续的元素，不会创建完整的数据集列表，从而节约了内存使用。\n",
    "\n",
    "** 练习：**现在让我们使用yield来构造一个reader()吧！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 读取训练数据或测试数据\n",
    "def read_data(data_set):\n",
    "    \"\"\"\n",
    "        一个reader\n",
    "        Args:\n",
    "            data_set -- 要获取的数据集\n",
    "        Return:\n",
    "            reader -- 用于获取训练数据集及其标签的生成器generator\n",
    "    \"\"\"\n",
    "    def reader():\n",
    "        \"\"\"\n",
    "        一个reader\n",
    "        Args:\n",
    "        Return:\n",
    "            data[:-1], data[-1:] -- 使用yield返回生成器(generator)，\n",
    "                    data[:-1]表示前n-1个元素，也就是训练数据，data[-1:]表示最后一个元素，也就是对应的标签\n",
    "        \"\"\"\n",
    "        for data in data_set:\n",
    "            ### START CODE HERE ### (≈ 2 lines of code)\n",
    "            pass\n",
    "            ### END CODE HERE ###\n",
    "    return reader\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "test_array for read_data:\n",
      "([1, 1, 1, 1], [0])\n",
      "([2, 2, 2, 2], [1])\n",
      "([3, 3, 3, 3], [0])\n"
     ]
    }
   ],
   "source": [
    "test_array = [[1,1,1,1,0],\n",
    "                [2,2,2,2,1],\n",
    "                [3,3,3,3,0]]\n",
    "\n",
    "print(\"test_array for read_data:\")\n",
    "for value in read_data(test_array)():\n",
    "    print(value)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**期望输出**: \n",
    "\n",
    "<table>\n",
    "  <tr>\n",
    "    <td>([1, 1, 1, 1], [0])</td>\n",
    "  </tr>\n",
    "  <tr>\n",
    "    <td>([2, 2, 2, 2], [1])</td> \n",
    "  </tr>\n",
    "    <td>([3, 3, 3, 3], [0])</td> \n",
    "  </tr>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4 - 训练过程\n",
    "\n",
    "完成了数据的预处理工作并构造了read_data()来读取数据，接下来将进入模型的训练过程，使用PaddlePaddle来定义构造可训练的Logistic回归模型，关键步骤如下：\n",
    "\n",
    "- 初始化\n",
    "\n",
    "- 配置网络结构和设置参数\n",
    "    - 配置网络结构\n",
    "    - 定义损失函数cost\n",
    "    - 创建parameters\n",
    "    - 定义优化器optimizer\n",
    "\n",
    "- 模型训练\n",
    "\n",
    "- 模型检验\n",
    "\n",
    "- 预测\n",
    "\n",
    "- 绘制学习曲线\n",
    "\n",
    "** （1）初始化 **\n",
    "\n",
    "首先进行最基本的初始化操作，在PaddlePaddle中使用paddle.init(use_gpu=False, trainer_count=1)来进行初始化：\n",
    "\n",
    "- use_gpu=False表示不使用gpu进行训练\n",
    "- trainer_count=1表示仅使用一个训练器进行训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化\n",
    "paddle.init(use_gpu=False, trainer_count=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** （2）配置网络结构和设置参数 **\n",
    "\n",
    "** 配置网络结构 **\n",
    "\n",
    "我们知道Logistic回归模型结构相当于一个只含一个神经元的神经网络，如下图所示，只包含输入数据以及输出层，不存在隐藏层，所以只需配置输入层(input)、输出层(predict)和标签层(label)即可。\n",
    "\n",
    "<img src=\"images/logistic.png\" width=\"200px\">\n",
    "\n",
    "** 练习：**接下来让我们使用PaddlePaddle提供的接口开始配置Logistic回归模型的简单网络结构吧，一共需要配置三层：\n",
    "\n",
    "** 输入层： **\n",
    "\n",
    "我们可以定义image=paddle.layer.data(name=”image”, type=paddle.data_type.dense_vector(data_dim))来表示生成一个数据输入层，名称为“image”，数据类型为data_dim维向量；\n",
    "\n",
    "在定义输入层之前，我们需要使用之前计算的num_px来获取数据维度data_dim，data_dim=num_px \\* num_px \\* 3\n",
    "\n",
    "** 输出层： **\n",
    "\n",
    "我们可以定义predict=paddle.layer.fc(input=image, size=1, act=paddle.activation.Sigmoid())表示生成一个全连接层，输入数据为image，神经元个数为1，激活函数为Sigmoid()；\n",
    "\n",
    "** 标签层 **\n",
    "\n",
    "我们可以定义label=paddle.layer.data(name=”label”, type=paddle.data_type.dense_vector(1))表示生成一个数据层，名称为“label”，数据类型为1维向量。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 配置网络结构\n",
    "\n",
    "\n",
    "# 数据层需要使用到数据维度data_dim，根据num_px来计算data_dim\n",
    "\n",
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "data_dim = None\n",
    "### END CODE HERE ###\n",
    "\n",
    "# 输入层，paddle.layer.data表示数据层\n",
    "\n",
    "image = None\n",
    "\n",
    "# 输出层，paddle.layer.fc表示全连接层\n",
    "\n",
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "predict = None\n",
    "### END CODE HERE ###\n",
    "\n",
    "# 标签数据层，paddle.layer.data表示数据层\n",
    "\n",
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "label = None\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** 定义损失函数 **\n",
    "\n",
    "在配置网络结构之后，我们需要定义一个损失函数来计算梯度并优化参数，在这里我们可以使用PaddlePaddle提供的交叉熵损失函数，定义cost = paddle.layer.multi_binary_label_cross_entropy_cost(input=predict, label=label)，使用predict与label计算成本。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 损失函数，使用交叉熵损失函数\n",
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "cost = None\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** 创建parameters **\n",
    "\n",
    "PaddlePaddle中提供了接口paddle.parameters.create(cost)来创建和初始化参数，参数cost表示基于我们刚刚创建的cost损失函数来创建和初始化参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建parameters\n",
    "\n",
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "parameters = None\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** optimizer **\n",
    "\n",
    "参数创建完成后，定义参数优化器optimizer= paddle.optimizer.Momentum(momentum=0, learning_rate=0.00002)，使用Momentum作为优化器，并设置动量momentum为零，学习率为0.00002。注意，暂时无需了解Momentum的含义，大家只需要学会使用即可。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#创建optimizer\n",
    "\n",
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "optimizer = None\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** 其它配置 **\n",
    "\n",
    "feeding={‘image’:0, ‘label’:1}是数据层名称和数组索引的映射，用于在训练时输入数据，costs数组用于存储cost值，记录成本变化情况。\n",
    "最后定义函数event_handler(event)用于事件处理，事件event中包含batch_id，pass_id，cost等信息，我们可以打印这些信息或作其它操作。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 数据层和数组索引映射，用于trainer训练时喂数据\n",
    "feeding = {\n",
    "        'image': 0,\n",
    "        'label': 1}\n",
    "\n",
    "# 记录成本cost\n",
    "costs = []\n",
    "\n",
    "# 事件处理\n",
    "def event_handler(event):\n",
    "    \"\"\"\n",
    "    事件处理器，可以根据训练过程的信息作相应操作\n",
    "\n",
    "    Args:\n",
    "        event -- 事件对象，包含event.pass_id, event.batch_id, event.cost等信息\n",
    "    Return:\n",
    "    \"\"\"\n",
    "    if isinstance(event, paddle.event.EndIteration):\n",
    "        if event.pass_id % 100 == 0:\n",
    "            print(\"Pass %d, Batch %d, Cost %f\" % (event.pass_id, event.batch_id, event.cost))\n",
    "            ### START CODE HERE ### (≈ 1 lines of code)\n",
    "                                    # add event.cost to costs\n",
    "            ### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** 模型训练 **\n",
    "\n",
    "上述内容进行了模型初始化、网络结构的配置并创建了损失函数、参数、优化器，接下来利用上述配置进行模型训练。\n",
    "\n",
    "\n",
    "首先定义一个随机梯度下降trainer，配置三个参数cost、parameters、update_equation，它们分别表示损失函数、参数和更新公式。\n",
    "\n",
    "再利用trainer.train()即可开始真正的模型训练，我们可以设置参数如下：\n",
    "\n",
    "<img src=\"images/code1.png\" width=\"500px\">\n",
    "\n",
    "- paddle.reader.shuffle(train(), buf_size=5000)表示trainer从train()这个reader中读取了buf_size=5000大小的数据并打乱顺序\n",
    "- paddle.batch(reader(), batch_size=256)表示从打乱的数据中再取出batch_size=256大小的数据进行一次迭代训练\n",
    "- 参数feeding用到了之前定义的feeding索引，将数据层image和label输入trainer，也就是训练数据的来源。\n",
    "- 参数event_handler是事件管理机制，读者可以自定义event_handler，根据事件信息作相应的操作。\n",
    "- 参数num_passes=5000表示迭代训练5000次后停止训练。\n",
    "\n",
    "** 练习：**定义trainer并开始训练模型（大家可以自己定义buf_size，batch_size，num_passes等参数，但是建议大家先参考上述的参数设置，在完成整个训练之后，再回过头来调整这些参数，看看结果会有什么不同）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Pass 0, Batch 0, Cost 0.718985\n",
      "Pass 100, Batch 0, Cost 0.497979\n",
      "Pass 200, Batch 0, Cost 0.431610\n",
      "Pass 300, Batch 0, Cost 0.386631\n",
      "Pass 400, Batch 0, Cost 0.352110\n",
      "Pass 500, Batch 0, Cost 0.324237\n",
      "Pass 600, Batch 0, Cost 0.301005\n",
      "Pass 700, Batch 0, Cost 0.281201\n",
      "Pass 800, Batch 0, Cost 0.264035\n",
      "Pass 900, Batch 0, Cost 0.248960\n",
      "Pass 1000, Batch 0, Cost 0.235580\n",
      "Pass 1100, Batch 0, Cost 0.223603\n",
      "Pass 1200, Batch 0, Cost 0.212803\n",
      "Pass 1300, Batch 0, Cost 0.203003\n",
      "Pass 1400, Batch 0, Cost 0.194064\n",
      "Pass 1500, Batch 0, Cost 0.185871\n",
      "Pass 1600, Batch 0, Cost 0.178331\n",
      "Pass 1700, Batch 0, Cost 0.171367\n",
      "Pass 1800, Batch 0, Cost 0.164913\n",
      "Pass 1900, Batch 0, Cost 0.158914\n"
     ]
    }
   ],
   "source": [
    "# 构造trainer\n",
    "\n",
    "### START CODE HERE ### (≈ 4 lines of code)\n",
    "trainer = paddle.trainer.SGD(\n",
    "    cost=None, \n",
    "    parameters=None, \n",
    "    update_equation=None)\n",
    "### END CODE HERE ###\n",
    "\n",
    "# 模型训练\n",
    "\n",
    "### START CODE HERE ### (≈ 7 lines of code)\n",
    "trainer.train(\n",
    "    reader=paddle.batch(\n",
    "        paddle.reader.shuffle(None, buf_size=None),\n",
    "        batch_size=None),\n",
    "    feeding=None,\n",
    "    event_handler=None,\n",
    "    num_passes=None)\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** 模型检验 **\n",
    "\n",
    "模型训练完成后，接下来检验模型的准确率。\n",
    "\n",
    "在这里我们首先需要定义一个函数get_data()来帮助我们获得用于检验模型准确率的数据，而数据的来源是read_data()返回的训练数据和测试数据。  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取数据\n",
    "def get_data(data_creator):\n",
    "    \"\"\"\n",
    "    使用参数data_creator来获取测试数据\n",
    "\n",
    "    Args:\n",
    "        data_creator -- 数据来源,可以是train()或者test()\n",
    "    Return:\n",
    "        result -- 包含测试数据(image)和标签(label)的python字典\n",
    "    \"\"\"\n",
    "    data_creator = data_creator\n",
    "    data_image = []\n",
    "    data_label = []\n",
    "\n",
    "    for item in data_creator():\n",
    "        data_image.append((item[0],))\n",
    "        data_label.append(item[1])\n",
    "\n",
    "    ### START CODE HERE ### (≈ 4 lines of code)\n",
    "    result = {\n",
    "        \"image\": data_image,\n",
    "        \"label\": data_label\n",
    "    }\n",
    "    ### END CODE HERE ###\n",
    "\n",
    "    return result\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获得数据之后，我们就可以开始利用paddle.infer()来进行预测，参数output_layer 表示输出层，参数parameters表示模型参数，参数input表示输入的测试数据。\n",
    "\n",
    "** 练习：**\n",
    "\n",
    "- 利用get_data()获取测试数据和训练数据\n",
    "\n",
    "- 使用paddle.infer()进行预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取测试数据和训练数据，用来验证模型准确度\n",
    "\n",
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "train_data = None\n",
    "test_data = None\n",
    "### END CODE HERE ###\n",
    "    \n",
    "# 根据train_data和test_data预测结果，output_layer表示输出层，parameters表示模型参数，input表示输入的测试数据\n",
    "\n",
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "probs_train = paddle.infer(\n",
    "    output_layer=predict, parameters=parameters, input=None    # input=训练数据\n",
    ")\n",
    "probs_test = paddle.infer(\n",
    "    output_layer=predict, parameters=parameters, input=None    # input=测试数据\n",
    ")\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获得检测结果probs_train和probs_test之后，我们将结果转化为二分类结果并计算预测正确的结果数量，定义train_accuracy和test_accuracy来分别计算训练准确度和测试准确度。注意，在test_accuracy中，我们不仅计算了准确度，并且传入了一个test_data_y数组参数用于存储预测结果，方便后续的查看。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 训练集准确度\n",
    "def train_accuracy(probs_train, train_data):\n",
    "    \"\"\"\n",
    "    根据训练数据集来计算训练准确度train_accuracy\n",
    "\n",
    "    Args:\n",
    "        probs_train -- 训练数据集的预测结果，调用paddle.infer()来获取\n",
    "        train_data -- 训练数据集\n",
    "\n",
    "    Return:\n",
    "        train_accuracy -- 训练准确度train_accuracy\n",
    "    \"\"\"\n",
    "    train_right = 0\n",
    "    train_total = len(train_data['label'])\n",
    "    for i in range(len(probs_train)):\n",
    "        if float(probs_train[i][0]) > 0.5 and train_data['label'][i] == 1:\n",
    "            train_right += 1\n",
    "        elif float(probs_train[i][0]) < 0.5 and train_data['label'][i] == 0:\n",
    "            train_right += 1\n",
    "    train_accuracy = (float(train_right) / float(train_total)) * 100\n",
    "\n",
    "    return train_accuracy\n",
    "\n",
    "\n",
    "# 测试集准确度\n",
    "def test_accuracy(probs_test, test_data, test_data_y):\n",
    "    \"\"\"\n",
    "    根据测试数据集来计算测试准确度test_accuracy\n",
    "\n",
    "    Args:\n",
    "        probs_test -- 测试数据集的预测结果，调用paddle.infer()来获取\n",
    "        test_data -- 测试数据集\n",
    "\n",
    "    Return:\n",
    "        test_accuracy -- 测试准确度test_accuracy\n",
    "    \"\"\"\n",
    "    test_right = 0\n",
    "    test_total = len(test_data['label'])\n",
    "    for i in range(len(probs_test)):\n",
    "        if float(probs_test[i][0]) > 0.5:\n",
    "            test_data_y.append(1)\n",
    "            if test_data['label'][i] == 1:\n",
    "                test_right += 1\n",
    "        elif float(probs_test[i][0]) < 0.5:\n",
    "            test_data_y.append(0)\n",
    "            if test_data['label'][i] == 0:\n",
    "                test_right += 1\n",
    "\n",
    "    test_accuracy = (float(test_right) / float(test_total)) * 100\n",
    "\n",
    "    return test_accuracy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "调用上述两个函数并输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train_accuracy: 98.5645933014 %\n",
      "test_accuracy: 70.0 %\n"
     ]
    }
   ],
   "source": [
    "# 计算train_accuracy和test_accuracy\n",
    "test_data_y = []\n",
    "\n",
    "### START CODE HERE ### (≈ 2 lines of code)\n",
    "print(\"train_accuracy: {} %\".format(None))    # 利用train_accuracy()计算训练集准确率\n",
    "print(\"test_accuracy: {} %\".format(None))     # 利用test_accuracy()计算测试集准确率\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** 期望输出：**\n",
    "\n",
    "<table style=\"width:40%\"> \n",
    "\n",
    "    <tr>\n",
    "        <td> **train_accuracy **  </td> \n",
    "        <td> $\\approx$ 98% </td>\n",
    "    </tr>\n",
    "\n",
    "    <tr>\n",
    "        <td> **test Accuracy**  </td> \n",
    "        <td> $\\approx$ 70% </td>\n",
    "    </tr>\n",
    "</table> \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "因为数据集和逻辑回归模型的限制，并且没有加入其它优化方式，所以70%的测试集准确率已经是相当好的结果，如果你也得到相似的结果，大约98%的训练集准确率和70%的测试集准确率，那么恭喜你到目前为止的工作都很棒，你已经配置了不错的模型和参数。当然你可以返回去调整一些参数，例如learning_rate/batch_size/num_passes，或者参考官方[PaddlePaddle文档](http://paddlepaddle.org/docs/develop/documentation/zh/getstarted/index_cn.html)来修改你的模型，尝试去犯错或者通过调参来得到更好的结果都能帮助你熟悉深度学习以及PaddlePaddle框架的使用！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** 学习曲线 **\n",
    "\n",
    "接下来我们利用之前保存的costs数据来输出成本的变化情况，利用学习曲线对模型进行分析。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7ff2e5e0fa50>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "costs = np.squeeze(costs)\n",
    "plt.plot(costs)\n",
    "plt.ylabel('cost')\n",
    "plt.xlabel('iterations (per hundreds)')\n",
    "plt.title(\"Learning rate = 0.00002\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到图中成本在刚开始收敛较快，随着迭代次数变多，收敛速度变慢，最终收敛到一个较小值。\n",
    "\n",
    "接下来，利用之前保存的测试结果test_data_y来对测试数据集中的单个图片进行预测，通过index来选择一张图片，看看你的模型是不是正确预测了这张图片吧！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "y = 0, you predicted that it is a \"non-cat\" picture.\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7ff2e56f4390>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Example of a picture that was wrongly classified.\n",
    "index = 14\n",
    "plt.imshow((np.array(test_data['image'][index])).reshape((64, 64, 3)))\n",
    "print (\"y = \" + str(test_data_y[index]) + \", you predicted that it is a \\\"\" + classes[test_data_y[index]].decode(\"utf-8\") +  \"\\\" picture.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5 - 总结\n",
    "\n",
    "通过这个练习我们应该记住：\n",
    "\n",
    "1. 数据预处理是训练模型之前的必需工作，有时候理解数据并做好预处理工作比构建模型需要更多时间和耐心！\n",
    "\n",
    "2. PaddlePaddle训练模型的基本步骤: \n",
    "\n",
    "    - 初始化\n",
    "\n",
    "    - 配置网络结构和设置参数：\n",
    "        - 定义成本函数cost\n",
    "        - 创建parameters\n",
    "        - 定义优化器optimizer\n",
    "    - 定义event_handler\n",
    "\n",
    "    - 定义trainer\n",
    "\n",
    "    - 开始训练\n",
    "\n",
    "    - 预测infer()并输出准确率train_accuracy和test_accuracy\n",
    "\n",
    "3. 练习中的许多参数可以作调整，例如修改学习率会对模型结果产生很大影响，大家可以在本练习或者后面的练习中多做些尝试。\n",
    "\n",
    "\n",
    "至此Logistic回归模型的训练工作完成，我们发现在使用PaddlePaddle进行模型配置和训练的过程中不用考虑参数的初始化、成本函数、激活函数、梯度下降、参数更新和预测等具体细节，只需要简单地配置网络结构和trainer即可，并且PaddlePaddle提供了许多接口来改变学习率、成本函数、批次大小等许多参数来改变模型的学习效果，使用起来更加灵活，方便测试，在之后的练习中，我们会对PaddlePaddle更加熟悉。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
